serde_tokenstream
This Rust crate is intended for use with macros that need bespoke configuration.
It's implemented as a serde::Deserializer
that operates on a
proc_macro2::TokenSteam
(easily converted from the standard
proc_macro::TokenStream
).
Usage
Say we're building an attribute proc macro that you want consumers to use like this:
It's also useful for function-like macros:
my_macro!;
The function that implements the proc macro must have two parameters (both of
type proc_macro::TokenStream
): attributes (the tokens with the braces that
follow the name of the macro), and the item (the function, type, etc. to
which the macro is applied):
We'll first define the struct
type that represents the configuration and
derive
a serde::Deserialize
:
Now we can parse attr
into the Config
struct with
serde_tokenstream::from_tokenstream
:
use TokenStream;
use from_tokenstream;
See the serde
documentation for the full range of controls that can be
applied to types and their members.
Error Handling
Errors indicate the problematic portion of consuming code to assist the macro consumer:
error: unknown variant `Fusion`, expected one of `Coal`, `Fission`, `Hydroelectric`
--> tests/test_err1.rs:7:16
|
7 | kind = Fusion,
| ^^^^^^
TokenStream and syn::* values
In some cases, it's useful to pass TokenStream values as parameters to a macro.
In this case we can use the TokenStreamWrapper
which is a wrapper around
TokenStream
that implements Deserialize
or ParseWrapper
which is a
wrapper around syn::Parse
that implements Deserialize
. The latter is useful
for passing in, for example, a syn::Path
, or other specific entities from the
syn
crate.
OrderedMap
You may want to use the map syntax with keys that cannot be used by types such
as HashMap
or BTreeMap
because they don't implement Hash
or Ord
. In
those cases, you can use an OrderedMap
and extract the pairs as an iterator
of tuples.
Let's say we we want our "keys" to be serde_json::Value
s and our value to
be... whatever... String
s! You can't use serde_json::Value
as the key in a
HashMap
or BTreeMap
, but we can for an OrderedMap
:
let config = ?;
The macro can then be invoked like this:
my_macro!;